/*
 * class ModelManager
 *
 * @created 24 avril 2007
 * @author adelaye
 *
 */
package objects;

import kernel.*;
import java.io.*;
import java.util.*;


public class ModelManager{
    
    private static ModelManager _instance = null;

    public static final int BASE = 0;
    public static final int MOBILE = 1;
    public static final int SINK = 2;
    public static final int SENSOR_NETWORK = 3;
    
    private String dir_path;
    private HashMap<String,DataMobileStation> _mobileModels;
    private HashMap<String,DataBaseStation> _baseModels;
    private HashMap<String,DataSensorNetwork> _sensorNetworkModels;
    private HashMap<String,DataSink> _sinkModels;

    private HashMap<String,DataType> _models;
    
    public static final String MODELNAME_PATTERN = "[A-Za-z_]+[.]model";
    public static final String MODELNAME_EXT = ".model";
    public static final String MODEL_DIR = "models" + File.separator;
    
    private DataType[] _currentModel;
    private String[] _currentModelName;
    
    public ModelManager(){
	
	_currentModel = new DataType[4];
	_currentModelName = new String[4];

	dir_path = this.getClass().getResource(".").getPath();
	File dir = new File(dir_path + MODEL_DIR);

	_models = new HashMap<String,DataType>();
	_baseModels = new HashMap<String,DataBaseStation>();
	_mobileModels = new HashMap<String,DataMobileStation>();
	_sensorNetworkModels = new HashMap<String,DataSensorNetwork>();
	_sinkModels = new HashMap<String,DataSink>();

	File[] files = dir.listFiles();
	
	if(files != null){
	    for(File f : files){
		String name = f.getName();
		if(!f.isDirectory() && name.matches(MODELNAME_PATTERN)){
		    try{
			FileInputStream fis = new FileInputStream(f);
			ObjectInputStream ois = new ObjectInputStream(fis);
			DataType model = (DataType)ois.readObject();
			String model_name = name.substring(0,name.length()-MODELNAME_EXT.length());
			if(model instanceof DataMobileStation && !(model instanceof DataSink)){
			    _mobileModels.put(model_name,(DataMobileStation)model);
			}else if(model instanceof DataBaseStation){
			    _baseModels.put(model_name,(DataBaseStation)model);
			}else if(model instanceof DataSink){
			    _sinkModels.put(model_name,(DataSink)model);
			}else if(model instanceof DataSensorNetwork){
			    _sensorNetworkModels.put(model_name,(DataSensorNetwork)model);
			}
		    }catch(IOException e){
			System.out.println(e.getMessage());
		    }catch(ClassNotFoundException e){
			System.out.println(e.getMessage());
		    }
		}
	    }
	}
	_instance = this;

	// initialisation des modeles "default"
	if(!_baseModels.containsKey("default")){
	    DataBaseStation d = new DataBaseStation();
	    _baseModels.put("default",d);
	    _currentModel[BASE]=d;
	    _currentModelName[BASE] = "default";
	}else{
	    _currentModel[BASE]=_baseModels.get("default");
	    _currentModelName[BASE] = "default";
	}
	
	if(!_mobileModels.containsKey("default")){
	    DataMobileStation d = new DataMobileStation();
	    _mobileModels.put("default",d);
	    _currentModel[MOBILE]=d;
	    _currentModelName[MOBILE] = "default";
	}else{
	    _currentModel[BASE]=_mobileModels.get("default");
	    _currentModelName[MOBILE] = "default";
	}

	if(!_sinkModels.containsKey("default")){
	    DataSink d = new DataSink();
	    _sinkModels.put("default",d);
	    _currentModel[SINK]=d;
	    _currentModelName[SINK] = "default";
	}else{
	    _currentModel[SINK]=_sinkModels.get("default");
	    _currentModelName[SINK] = "default";
	}

	if(!_sensorNetworkModels.containsKey("default")){
	    DataSensorNetwork d = new DataSensorNetwork();
	    _sensorNetworkModels.put("default",d);
	    _currentModel[SENSOR_NETWORK] = d;
	    _currentModelName[SENSOR_NETWORK] = "default";
	}else{
	    _currentModel[SENSOR_NETWORK]=_sensorNetworkModels.get("default");
	    _currentModelName[SENSOR_NETWORK] = "default";
	}

    }

    public static ModelManager getModelManager(){
	if(_instance==null){
	    return new ModelManager();
	}else{
	    return _instance;
	}
    }


    public void addModel(String name, DataType model) {
	try{
	    if(name == "default"){
		name = "user_default";
	    }

	    File f = new File(dir_path + MODEL_DIR + name + MODELNAME_EXT);
	    FileOutputStream fos = new FileOutputStream(f);
	    ObjectOutputStream oos = new ObjectOutputStream(fos);
	    oos.writeObject(model);
	    oos.flush();
	    oos.close();
	    FileInputStream fis = new FileInputStream(f);
	    ObjectInputStream ois = new ObjectInputStream(fis);
	    DataType mod = (DataType)ois.readObject();
	    int type;

	    if(mod instanceof DataSink){
		type = SINK;
		_sinkModels.put(name,(DataSink)mod);
		setCurrentModel(name,type);
	    }
	    if(mod instanceof DataMobileStation){
		type = MOBILE;
		_mobileModels.put(name,(DataMobileStation)mod);
		setCurrentModel(name,type);
	    }
	    if(mod instanceof DataBaseStation){
		type = BASE;
		_baseModels.put(name,(DataBaseStation)mod);
		setCurrentModel(name,type);
	    }
	    if(mod instanceof DataSensorNetwork){
		type = SENSOR_NETWORK;
		_sensorNetworkModels.put(name,(DataSensorNetwork)mod);
		setCurrentModel(name,type);
	    }


	}catch(IOException e){
	    System.out.println(e.getMessage());
	}catch(ClassNotFoundException e){
	    System.out.println(e.getMessage());
	}   
    }

    public HashMap<String,DataMobileStation> getMobileModels(){
	return _mobileModels;
    }
    
    public HashMap<String,DataBaseStation> getBaseModels(){
	return _baseModels;
    }
    
    public HashMap<String,DataSink> getSinkModels(){
	return _sinkModels;
    }
    
    public HashMap<String,DataSensorNetwork> getSensorNetworkModels(){
	return _sensorNetworkModels;
    }

    public HashMap getModels(int type){
	switch(type){
	case BASE:
	    return _baseModels;
	case MOBILE:
	    return _mobileModels;
	case SINK:
	    return _sinkModels;
	case SENSOR_NETWORK:
	    return _sensorNetworkModels;
	default:
	    return _baseModels;
	}
    }

    public void setCurrentModel(String s, int type){
	DataType data = _models.get(s);
	_currentModel[type] = data;
	_currentModelName[type] = s;
    }

    public DataType getCurrentModel(int type){
	DataType d;

	// filling transient attributes with empty objects
	switch(type){
	case BASE:
	    d = _baseModels.get(_currentModelName[BASE]);
	    ((DataBaseStation)d).setWishedEmission(new Vector());
	    return d;
	case MOBILE:
	    d = _mobileModels.get(_currentModelName[MOBILE]);
	    ((DataMobileStation)d).setWishedEmission(new Vector());
	    ((DataMobileStation)d).setWishedEmission3(new Vector());
	    ((DataMobileStation)d).setActivities(new Stack());
	    return d;
	case SINK:
	    d = _sinkModels.get(_currentModelName[SINK]);
	    ((DataSink)d).setRequests(new Vector<DataInterest>());
	    ((DataSink)d).setWishedEmission(new Vector());
	    ((DataSink)d).setWishedEmission3(new Vector());
	    ((DataSink)d).setActivities(new Stack());
	    return d;
	case SENSOR_NETWORK:
	    d = _sensorNetworkModels.get(_currentModelName[SENSOR_NETWORK]);
	    return d;
	}
	return null;
    }

}
